import React, { useState, useCallback, useEffect } from 'react';
import { Common } from 'UtilsCommon';
import { useGetDataSourceOptions } from 'UseHooks';
import { Checkbox, List } from 'antd-mobile';
import TextBox from './textBox';
import Base from './base';
import * as styles from '../styles/view.scss';

const getOptions = (property, view, pageAxis, parentValue) => {
    Base.setValueTextName(property);

    const { dataSource, valueName, textName } = property;

    const options = [];

    dataSource.forEach(d => {
        const value = d[valueName];
        const label = d[textName];
        options.push({ value, label, data: d, inputProperty: d.inputProperty });
    });

    return options;
};

const renderItem = (isList, m, i, value, onChange, onClickItem, property, pageId, onInputClick, isReadOnly) => {
    if (isList) {
        return <List.Item key={i} style={{ '--active-background-color': '#ffffff' }} onClick={(e) => onClickItem(e, m)} arrow={false}>
            {renderCheckboxItem(m, i, value, null, property, pageId, onInputClick, isReadOnly)}
        </List.Item>;
    }
    return renderCheckboxItem(m, i, value, onChange, property, pageId, onInputClick, isReadOnly);
};

const renderCheckboxItem = (m, i, value, onChange, property, pageId, onInputClick, isReadOnly) => {
    m.checked = value.includes(m.value);
    if (m.inputProperty) m.inputProperty.isReadOnly = isReadOnly;
    return <React.Fragment key={i}>
        {onChange && <Checkbox checked={m.checked} onChange={(e) => onChange && onChange(e, m)}>{m.label}</Checkbox>}
        {!onChange && <Checkbox checked={m.checked}>{m.label}</Checkbox>}
        {m.checked && m.inputProperty && <div className={styles.divCheckboxItemInput} onClick={onInputClick}><TextBox property={m.inputProperty} view={property} pageId={pageId} /></div>}
    </React.Fragment>;
};

const renderOptions = (isList, options, value, onChange, onClickItem, property, pageId, onInputClick, isReadOnly) => {
    return options.map((m, i) => renderItem(isList, m, i, value, onChange, onClickItem, property, pageId, onInputClick, isReadOnly));
};

const valueChange = (property, view, pageAxis, value) => {
    if (property.valueChange) property.valueChange(value, Base.getSelectData(property, value));

    if (property.valueVisibleProperties) Base.setValueVisibleProperties(property, view, value);
};

const getValue = (v, property, options) => {
    if (property.isArray) return v;
    else if (!property.isObjValue) return v.join(',');
    const obj = { checkedValues: v, inputValues: {} };
    options.forEach(d => {
        if (d.checked && d.inputProperty) {
            obj.inputValues[d.inputProperty.name] = d.inputProperty.getValue();
        }
    });
    return obj;
};

const setValue2 = (v, options, setValue) => {
    if (v && typeof v === 'string') v = v.split(',');
    const { checkedValues, inputValues } = v || {};
    if (inputValues) {
        options.forEach(d => {
            if (d.inputProperty) d.inputProperty.value = inputValues[d.inputProperty.name];
        });
    }

    setValue(checkedValues || v || []);
};

const setCheckedValue = (setValue, value, m, options, property, pageAxis) => {
    if (property.isMultiple) {
        let checked = false;
        if (value.includes(m.value)) {
            value = value.filter(f => !Common.isEquals(f, m.value));
        }
        else {
            value = value.map(m => m);
            value.push(m.value);
            checked = true;
        }
        if (property.maxItemCount > 0 && value.length > property.maxItemCount) {
            pageAxis.alert('最多只能选择' + property.maxItemCount + '项');
            return;
        }

        m.checked = checked;
    }
    else {
        if (value.length > 0 && m.value === value[0]) {
            if (property.isNullable) value = [];
            else return;
        }
        else value = [m.value];

        options.forEach(d => {
            d.checked = false;
        });
        if (value.length > 0) m.checked = true;
    }
    setValue(value);
    Base.bindDataValue(property, getValue(value, property, options));
};

const judgeNullable = (property, value, options) => {
    if (!value || value.length === 0) return property.nullTipMessage;
    let isEmpty = false;

    let p = null;
    for (let i = 0; i < options.length; i++) {
        p = options[i];
        if (p.checked && p.inputProperty) {
            const v = p.inputProperty.getValue();
            if (Common.isNullOrEmpty(v)) {
                isEmpty = true;
                p.inputProperty.setIsEmptyTip(true);
            }
        }
    }
    return isEmpty ? property.nullTipMessage : '';
};

const renderLabel = (displayIndex, label2, isRed2, isSetAll, isAll, onAll) => {
    return <div className={styles.divLabel}>
        {isRed2 ? <span style={{ color: 'red', position: 'relative', paddingRight: '0.125rem', top: '0.125rem' }}>*</span> : ''}
        <span>{displayIndex > 0 ? `${displayIndex}、` : ""}{label2}</span>
        {isSetAll && <Checkbox checked={isAll} onChange={onAll}>全选</Checkbox>}
    </div>;
};

const renderEmptyTip = (isEmptyTip, value) => {
    return <div className={styles.divEmptyTip}>
        {isEmptyTip && (!value || value.length === 0) && <span>请勾选选项</span>}
    </div>;
};

const getInitValue = (property) => {
    if (!property.value) return [];
    if (typeof property.value === 'string') return property.value.split(',');
    if (property.value && property.value.length > 0) return property.value;
    return [];
};

const getIsAll = (options, value) => {
    if (options.length === 0) return false;
    const obj = {};
    for (let i = 0; i < value.length; i++) {
        obj[value[i]] = true;
    }

    for (let i = 0; i < options.length; i++) {
        if (!obj[options[i].value]) return false;
    }
    return true;
};

const getSelectValue = (value, options, checked) => {
    if (checked) {
        value = value.map(m => m);
        options.forEach(d => {
            if (!value.includes(d.value)) value.push(d.value);
        });
    }
    else value = value.filter(f => !options.some(d => d.value === f));
    return value;
};

export default (props) => {
    const { property, view, pageId, pageAxis } = Base.getProps(props);

    const [value, setValue] = useState(getInitValue(property));
    const [isVisible, setIsVisible] = useState(property.isVisible !== false);
    const [isReadOnly, setIsReadOnly] = useState(!!property.isReadOnly);
    const [isEmptyTip, setIsEmptyTip] = useState(false);

    const [options, setOptions] = useGetDataSourceOptions(property, view, pageAxis, getOptions, property.id);

    const onChange = useCallback((e, m) => {
        if (isReadOnly) return;
        setCheckedValue(setValue, value, m, options, property, pageAxis);
        property.changeChecked && property.changeChecked(m);
    }, [property, pageAxis, setValue, value, options, isReadOnly]);

    const onAll = useCallback((checked) => {
        const v = getSelectValue(value, options, checked);
        setValue(v);
        property.changeAllChecked && property.changeAllChecked(options, checked);
        Base.bindDataValue(property, getValue(v, property, options));
    }, [property, value, setValue, options]);

    const onClickItem = useCallback((e, m) => {
        if (isReadOnly) return;
        if (e.target.nodeName !== 'INPUT' && !property.isInputClick) {
            setCheckedValue(setValue, value, m, options, property, pageAxis);
        }
        property.isInputClick = false;
    }, [property, pageAxis, setValue, value, options, isReadOnly]);

    const onInputClick = useCallback((e) => {
        property.isInputClick = true;
    }, [property]);

    useEffect(() => {
        options.length > 0 && valueChange(property, view, pageAxis, value);
    }, [property, view, pageAxis, value, options]);

    property.isSelect = true;
    property.setIsVisible = (v) => { property.isVisible = v; setIsVisible(v); };
    property.setValue = (v) => setValue2(v, options, setValue);
    property.getValue = () => getValue(value, property, options);
    property.getSelectData = () => Base.getSelectData(property, value);
    property.refreshOptions = (v) => setOptions(getOptions(property, view, pageAxis));
    property.setIsReadOnly = (v) => setIsReadOnly(v);
    property.judgeNullable = () => judgeNullable(property, value, options);
    property.setIsEmptyTip = (v) => setIsEmptyTip(v);

    const isAll = options.length > 0 && getIsAll(options, value);

    if (property.allPropertyName) {
        if (!property.isAllProperty) {
            property.isAllProperty = pageAxis.getProperty(property.allPropertyName);
        }
        if (property.isAllProperty) {
            property.isAllProperty.onChange = (v) => {
                onAll(v);
            };

            const v = isAll ? 1 : 0;
            if (property.isAllProperty.value !== v) {
                property.isAllProperty.value = v;
                if (property.isAllProperty.setValue) {
                    setTimeout(() => property.isAllProperty.setValue(v), 100);
                }
            }
        }
    }

    if (!isVisible) return null;

    const { isList, label, isRed } = property;
    let isNullable = property.isNullable;

    let isRed2 = property.isRed2 || (isNullable === false && isRed);
    if (isReadOnly) {
        isRed2 = false;
        isNullable = true;
        property.placeHolder = '';
    }

    return <div className={property.className} style={Base.setStyle(property.style)}>
        {label && renderLabel(property.displayIndex, label, isRed2, property.isSetAll, isAll, onAll)}
        {isList && <List style={property.style} mode="card" >
            {renderOptions(true, options, value, onChange, onClickItem, property, pageId, onInputClick, isReadOnly)}
        </List>}
        {!isList && <div className='divItems'>{renderOptions(false, options, value, onChange, onClickItem, property, pageId, onInputClick, isReadOnly)}</div>}
        {isEmptyTip && renderEmptyTip(isEmptyTip, value)}
    </div>;
};